package com.jinzhi.oss.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.jinzhi.common.utils.DateUtils;
import com.jinzhi.common.utils.Result;
import com.jinzhi.oss.domain.MinioProperty;
import com.jinzhi.oss.utils.MinioUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jinzhi.oss.dao.SysMinioDao;
import com.jinzhi.oss.domain.SysMinioDO;
import com.jinzhi.oss.service.SysMinioService;
import com.jinzhi.common.base.CoreServiceImpl;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * <pre>
 * minio大文件唯一性校验表
 * </pre>
 * <small> 2023-12-17 01:17:44 | lance</small>
 */
@Service
public class SysMinioServiceImpl extends CoreServiceImpl<SysMinioDao, SysMinioDO> implements SysMinioService {

    @Autowired
    private MinioUtil minioUtil;

    @Autowired
    private MinioProperty minioProperty;

    /**
     * 校验文件是否已经上传
     * @param md5 文件md5值
     * @return
     */
    @Override
    public Result<String> register(String md5) {
        //通过md5值查询数据库 是否存在已经上传的数据
        String filePath = null;
        Wrapper<SysMinioDO> wrapper = new EntityWrapper<SysMinioDO>().eq("md5", md5);
        List<SysMinioDO> list = this.selectList(wrapper);
        if(!list.isEmpty()){
            for (SysMinioDO sysMinioDO : list) {
                //在通过桶和文件名称去minio判断该文件是否存在
                Boolean isExist = minioUtil.checkFileIsExist(sysMinioDO.getBucketName(), sysMinioDO.getFileName());
                if(isExist){
                    filePath = minioProperty.getEndpoint() + "/" + sysMinioDO.getBucketName() + "/" + sysMinioDO.getFileName();
                    break;
                }
            }
        }
        return Result.ok(filePath);

    }

    /**
     * 切片上传
     * @param file 文件
     * @param md5 文件md5
     * @param index 当前切片名称 1、2、3、4......
     * @return
     */
    @Override
    public Result<String> uploadChunk(MultipartFile file, String md5, String index) {
        //先判断桶存不存在
        boolean exists = minioUtil.bucketExists(md5);
        if(!exists){
            minioUtil.createBucketName(md5);
        }
        return minioUtil.minioUpload(file, index, md5);
    }

    /**
     * 合并切片
     * @param md5 文件md5值
     * @param fileName 文件名称
     * @return
     */
    @Override
    public Result<String> mergeChunks(String md5, String fileName) {
        try {
            String bucketName = minioProperty.getBucketName();
            fileName = DateUtils.format(new Date(), DateUtils.DATE_PATTERN_11) + "/" + fileName.replaceAll(" ", "_");
            boolean b = minioUtil.merge(md5, bucketName, fileName);
            if (!b){
                //合并失败
                return Result.fail("文件上传异常！切片合并失败！");
            }
            //校验md5
//        boolean checkMd5 = checkMd5(bucketName,fileName,md5);
//        if (!checkMd5){
//            //删除合并后的文件
//            minioUtil.deleteFile(bucketName,fileName);
//            return Result.fail("切片合并失败！md5不匹配");
//        }
            //将md5存入数据库
            SysMinioDO sysMinioDO = new SysMinioDO();
            sysMinioDO.setBucketName(bucketName);
            sysMinioDO.setMd5(md5);
            sysMinioDO.setFileName(fileName);
            this.insert(sysMinioDO);
            //删除临时桶下面的所有临时文件
            minioUtil.deleteBucketFile(md5);
            //删除临时桶
            minioUtil.deleteBucketName(md5);
            //返回合并后的文件地址
            String filePath =  minioProperty.getEndpoint() + "/" + bucketName + "/" + fileName;
            return Result.ok(filePath);
        }catch (Exception e){
            return Result.fail("文件上传异常！切片合并失败！");
        }
    }


    /**
     * 查询文件上传进度，方便做断点续传
     * @param md5 文件md5值
     * @return
     */
    @Override
    public Result<String> uploadSchedule(String md5) {
        //查询临时桶是否存在（md5值就是临时桶的名称）
        boolean b = minioUtil.bucketExists(md5);
        if (!b) {
            return Result.ok();
        }
        //查询桶中的所有切片
        //已经上传的最大的切片（即1、2、3、4则返回4，续传从5开始）
        Integer index = null;
        try {
            List<String> folderList = minioUtil.getFolderList(md5);
            if (!folderList.isEmpty()) {
                index = folderList.stream()
                        .map(Integer::valueOf) // 将每个字符串转换为Integer
                        .max(Integer::compare).get(); // 找到最大值
            }
        } catch (Exception e) {
            return Result.fail("文件续传失败！");
        }
        return Result.ok(String.valueOf(index));
    }


    /**
     * 校验md5是否匹配
     * @param bucketName
     * @param fileName
     * @param md5
     * @return
     */
    private boolean checkMd5(String bucketName,String fileName, String md5) {
        try {
            //利用apache工具类获取文件md5值
            InputStream inputStream = minioUtil.getFileInputStream(bucketName, fileName);
            String md5Hex = DigestUtils.md5Hex(inputStream);
            if (md5.equalsIgnoreCase(md5Hex)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}
